#include "soft_uart.h"

// ?????? - ????
static uint8_t CalculateOddParity(uint8_t data) {
    uint8_t count = 0;
    for (int i = 0; i < 8; i++) {
        count += (data >> i) & 0x01;
    }
    return (count % 2) ? 0 : 1;  // ???:1???????????0
}

// ???????
void SoftUART_Init(SoftUART_HandleTypeDef* huart, 
                   GPIO_TypeDef* tx_port, uint16_t tx_pin, 
                   TIM_HandleTypeDef* timer, 
                   SoftUART_ParityTypeDef parity) {
    huart->tx_port = tx_port;
    huart->tx_pin = tx_pin;
    huart->timer = timer;
    huart->parity = parity;
    huart->is_sending = false;
    
    // 82MHz??,19200?????
    huart->bit_time = 102;
    
    // ??GPIO
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = tx_pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(tx_port, &GPIO_InitStruct);
    
    // ???????
    HAL_GPIO_WritePin(huart->tx_port, huart->tx_pin, GPIO_PIN_SET);
    
    // ?????
    __HAL_TIM_SET_PRESCALER(huart->timer, 41);
    __HAL_TIM_SET_AUTORELOAD(huart->timer, huart->bit_time - 1);
    __HAL_TIM_SET_COUNTER(huart->timer, 0);
}

// ?????? - ????,??LSB-first
void SoftUART_WriteByte(SoftUART_HandleTypeDef* huart, uint8_t data) {
    // ?????????
    while (huart->is_sending) {
        __NOP();
    }
    
    // ??????
    uint8_t parity_bit = CalculateOddParity(data);
    
    // ????? - ????:???LSB-first??
    // ???:???(0) + 8???(LSB-first) + ???? + ???(1)
    uint16_t frame = 0;
    
    // ??1:????????
    // ???:bit0 = 0
    // ???:bit1=LSB(bit0), bit2=bit1, ..., bit8=MSB(bit7)
    // ???:bit9
    // ???:bit10
    
    // ????? (bit0 = 0)
    // frame????0,????????0
    
    // ????? - LSB-first
    // ??bit0????bit1,??bit1????bit2,...,??bit7????bit8
    for (int i = 0; i < 8; i++) {
        if (data & (1 << i)) {  // ??????i?
            frame |= (1 << (i + 1));  // ?????(i+1)?
        }
    }
    
    // ????? (bit9)
    if (parity_bit) {
        frame |= (1 << 9);
    }
    
    // ????? (bit10)
    frame |= (1 << 10);
    
    // ???:11?
    uint8_t total_bits = 11;
    
    // ??????
    huart->tx_frame = frame;
    huart->tx_bit_count = total_bits;
    huart->is_sending = true;
    
    // ?????
    __HAL_TIM_SET_COUNTER(huart->timer, 0);
    HAL_TIM_Base_Start_IT(huart->timer);
}

// ????????? - ???????
void SoftUART_TimerCallback(SoftUART_HandleTypeDef* huart) {
    if (!huart->is_sending) {
        HAL_TIM_Base_Stop_IT(huart->timer);
        return;
    }
    
    if (huart->tx_bit_count > 0) {
        // ????:?????????????
        // ????????? = 11 - tx_bit_count
        uint8_t bit_to_send = 11 - huart->tx_bit_count;
        uint8_t current_bit = (huart->tx_frame >> bit_to_send) & 0x01;
        
        HAL_GPIO_WritePin(huart->tx_port, huart->tx_pin, current_bit ? GPIO_PIN_SET : GPIO_PIN_RESET);
        
        huart->tx_bit_count--;
    } else {
        // ????
        HAL_TIM_Base_Stop_IT(huart->timer);
        huart->is_sending = false;
        HAL_GPIO_WritePin(huart->tx_port, huart->tx_pin, GPIO_PIN_SET);
    }
}

// ????????
void SoftUART_WriteString(SoftUART_HandleTypeDef* huart, const char* str) {
    while (*str) {
        SoftUART_WriteByte(huart, (uint8_t)*str);
        str++;
        while (huart->is_sending) { __NOP(); }
        for (volatile uint32_t i = 0; i < 1000; i++) { __NOP(); }
    }
}

void SoftUART_WriteBuffer(SoftUART_HandleTypeDef* huart, uint8_t* buffer, uint16_t length) {
    for (uint16_t i = 0; i < length; i++) {
        SoftUART_WriteByte(huart, buffer[i]);
        while (huart->is_sending) { __NOP(); }
        for (volatile uint32_t i = 0; i < 1000; i++) { __NOP(); }
    }
}

bool SoftUART_IsBusy(SoftUART_HandleTypeDef* huart) {
    return huart->is_sending;
}